﻿/*
 * discretemgr.cpp
 *
 *  Created on: 2017年3月27日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_SCADA DM_API_EXPORT

#include <dm/scada/discretemgr.hpp>

#include <dm/scada/scadainfo.hpp>
#include <dm/scada/devicemgr.hpp>

#include <dm/os/log/logger.hpp>
#include <dm/datetime.hpp>

namespace dm{
namespace scada{

static const char* logModule = "CDiscreteMgr.scada.dm";

CDiscreteMgr::CDiscreteMgr( CScada& scada ):CScada(scada),
		m_cfg(scada.discreteInfos(),scada.info()->discreteCount()){
}

CDiscreteMgr& CDiscreteMgr::ins(){
	static CDiscreteMgr i(CScada::ins());
	return i;
}

/**
 * 设置描述
 * @param idx
 * @param str
 * @return
 */
bool CDiscreteMgr::setDesc( const index_t& idx,const char* str ){
	SDiscreteInfo* p = m_cfg.at(idx);
	if( p ){
		p->desc = str;
		return true;
	}else
		return false;
}

/**
 * 设置存盘标志
 * @param idx
 * @param s
 * @return
 */
bool CDiscreteMgr::setFlagSave( const index_t& idx,bool s ){
	SDiscreteInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagSave(s);
		return true;
	}else
		return false;
}

/**
 * 设置产生时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CDiscreteMgr::setFlagGenTimed( const index_t& idx,bool s ){
	SDiscreteInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagGenTimed(s);
		return true;
	}else
		return false;
}

/**
 * 设置上报时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CDiscreteMgr::setFlagReportTimed( const index_t& idx,bool s ){
	SDiscreteInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagReportTimed(s);
		return true;
	}else
		return false;
}

/**
 * 获取实时数据对应的离散量索引号
 * @param value
 * @return
 */
index_t CDiscreteMgr::indexOfRt( const rt_t* value )const{
	if( value<discretes() || value>discretes()+size() )
		return Idx_Inv;
	return value - discretes();
}

/**
 * 获取实时数据对应的离散量索引号
 * @param value
 * @return
 */
index_t CDiscreteMgr::indexOfRt( const volatile rt_t* value )const{
	if( value<discretes() || value>discretes()+size() )
		return Idx_Inv;
	return value - discretes();
}

/**
 * 获取离散量数据对应的描述信息
 * @param idx 离散量索引
 * @param value 离散量的值
 * @return
 */
const char* CDiscreteMgr::valueDesc( const index_t& idx,const CDiscrete::value_t& value )const{
	const SDiscreteInfo* p = info(idx);
	if( p ){
		if( value>=p->desc_num )
			return "无效值";
		return CDiscreteDescMgr::ins().desc(p->desc_pos+value);
	}else{
		return "无效索引";
	}
}

/**
 * 获取离散量所属设备索引
 * @param idx 离散量索引
 * @return
 */
index_t CDiscreteMgr::deviceIndex( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return Idx_Inv;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfDiscrete<=idx &&
				(d.info(i)->posOfDiscrete+d.info(i)->sizeOfDiscrete)>idx )
			return i;
	}

	return Idx_Inv;
}

const char* CDiscreteMgr::deviceDesc( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return NULL;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfDiscrete<=idx &&
				(d.info(i)->posOfDiscrete+d.info(i)->sizeOfDiscrete)>idx )
			return d.info(i)->desc.c_str();
	}

	return NULL;
}

/**
 * 获取离散量实时值描述
 * @param idx 离散量索引
 * @return
 */
const char* CDiscreteMgr::rtDesc( const index_t& idx ){
	return valueDesc(idx,rtValue(idx));
}

/**
 * 更新离散量实时数据
 * 本操作会产生事件信息。
 * @param idx 离散量索引
 * @param value 值
 * @param ds 数据产生原因
 * @param ts 数据时标
 * @return 是否更新成功
 */
bool CDiscreteMgr::update( const index_t& idx,const CDiscrete& value,const EDataSource& ds,const dm::CTimeStamp& ts ){
	if( idx<0 || idx>=size() ){
		log().warnning(THISMODULE "离散量索引溢出%d>=%d",idx,size());
		return false;
	}

	if( discretes()[idx].update(value,ds,ts) && info(idx)->isFlagGenTimed() ){
		CEvent e(CEvent::Discrete,idx,ts);
		e.value.discrete = value.getValue();
		CEventMgr::ins().gen(e);
	}

	return true;
}

bool CDiscreteMgr::set( const index_t& idx,const CDiscrete& value,const EDataSource& ds,const dm::CTimeStamp& ts ){
	if( idx<0 || idx>=size() ){
		log().warnning(THISMODULE "离散量索引溢出%d>=%d",idx,size());
		return false;
	}

	discretes()[idx].update(value,ds,ts);

	return true;
}

bool CDiscreteMgr::gen( const index_t& idx,const CDiscrete& value,const dm::CTimeStamp& ts ){
	if( idx<0 || idx>=size() ){
		log().warnning(THISMODULE "离散量索引溢出%d>=%d",idx,size());
		return false;
	}

	CEvent e(CEvent::Discrete,idx,ts);
	e.value.discrete = value.getValue();
	CEventMgr::ins().gen(e);

	return true;
}

/**
 * 格式化输出离散量信息
 * @param idx 离散量索引
 * @param ostr 输出流
 */
void CDiscreteMgr::printInfo( const index_t& idx,std::ostream& ostr )const{
	const SDiscreteInfo* p = info(idx);
	if( p ){
		ostr <<"ID:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()<<" [";
		for( int i=0;i<p->desc_num-1;++i ){
			ostr << CDiscreteDescMgr::ins().desc(p->desc_pos+i)<<'|';
		}

		ostr << CDiscreteDescMgr::ins().desc(p->desc_pos+p->desc_num-1)
				<<"]"
				<<" 存盘:";
		if( p->isFlagSave() )
			ostr <<"允许";
		else
			ostr <<"禁止";

		ostr <<" 产生时标数据:";
		if( p->isFlagGenTimed() )
			ostr <<"是";
		else
			ostr <<"否";

		ostr <<" 上报时标数据:";
		if( p->isFlagReportTimed() )
			ostr <<"是";
		else
			ostr <<"否";
	}else{
		ostr <<"无效索引("<<idx<<')';
	}
}

/**
 * 格式化输出离散量信息及实时值
 * @param idx 离散量索引
 * @param ostr 输出流
 */
void CDiscreteMgr::printInfoValue( const index_t& idx,std::ostream& ostr ){
	const SDiscreteInfo* p = info(idx);
	if( p ){
		rt_t* pv = rt(idx);

		ostr <<"ID:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()
				<<" 值:"<<pv->getValue().getValue()
				<<" 值描述:"<<valueDesc(idx,pv->getValue().getValue())
				<<" 数据方式:"<<pv->getDataSource()
				<<" 码值:"<<pv->getValue().getRaw()
				<<" 时标:"<<dm::CDateTime(pv->getTimeStamp()).toString().c_str();
	}else{
		ostr <<"无效索引("<<idx<<')';
	}
}
}
}
